home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1996 #15
/
Monster Media Number 15 (Monster Media)(July 1996).ISO
/
prog_d
/
tpop3.zip
/
MIME.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1996-03-15
|
12KB
|
544 lines
unit Mime;
interface
uses Classes,SysUtils,Forms,Dialogs;
const
MaxChars = 57;
type
TBinBytes = array[1..MaxChars] of byte;
TTxtBytes = array[1..2*MaxChars] of byte;
T24Bits = array[0..8*MaxChars] of boolean;
EUUInvalidCharacter = class(Exception)
constructor Create;
end;
EMIMEError = class(Exception);
{$IFDEF UseHuge}
TTextStream = class(TMemoryStream)
public
procedure Write(const s : string);
procedure Read(var s : string);
end;
{$ENDIF}
TBase64 = class
private
{$IFDEF UseHuge}
TextStream : TTextStream;
{$ELSE}
TextStream : TStringList;
{$ENDIF}
Stream : TStream;
CurSection : byte;
A24Bits : T24Bits;
FOnProgress : TNotifyEvent;
FOnStart : TNotifyEvent;
FOnEnd : TNotifyEvent;
function GenerateTxtBytes(tb : TBinBytes; NumOfBytes : byte) : string;
procedure GenerateBinBytes(InS : string; BufPtr : pointer;
var BytesGenerated : word);
function ByteFromTable(Ch : Char) : byte;
procedure DoProgress(Sender : TObject);
procedure DoStart(Sender : TObject);
procedure DoEnd(Sender : TObject);
public
Progress : Integer;
ProgressStep : Integer;
Canceled : boolean;
Table : string;
{$IFDEF UseHuge}
constructor Create(AStream : TStream; ATextStream : TTextStream);
{$ELSE}
constructor Create(AStream : TStream; ATextStream : TStringList);
{$ENDIF}
procedure Encode;
procedure Decode;
property OnProgress : TNotifyEvent read FOnProgress
write FOnProgress;
property OnStart : TNotifyEvent read FOnStart write FOnStart;
property OnEnd : TNotifyEvent read FOnEnd write FOnEnd;
end;
TQuotedPrintable = class(TComponent)
private
{ Private declarations }
protected
{ Protected declarations }
Stream : TStream;
Lines : TStringList;
procedure ReplaceHiChars(var s : string);
procedure ReplaceHex(var s : string);
procedure ReformatParagraph(Buf : PChar; Len : Integer;
TL : TStringList);
public
{ Public declarations }
Canceled : boolean;
constructor Create(AStream : TStream; ALines : TStringList);
procedure Encode;
procedure Decode;
published
{ Published declarations }
end;
function GetContentType(const FileName : string) : string;
function MakeUniqueID : string;
implementation
constructor EUUInvalidCharacter.Create;
begin
inherited Create('Invalid character in the input file');
end;
{$IFDEF UseHuge}
{TTextStream}
procedure TTextStream.Write(const s : string);
var
Buf : array[0..255] of Char;
sLen : byte absolute s;
begin
StrPCopy(@Buf,Concat(s,^M^J));
inherited Write(Buf,StrLen(@Buf));
end;
procedure TTextStream.Read(var s : string);
var
sLen : byte absolute s;
Ch : Char;
begin
Ch:=#00; s:='';
repeat
inherited Read(Ch,1);
if not (Ch in [^M,^J]) then
s:=Concat(s,Ch);
until Ch=^J;
end;
{$ENDIF}
{implementation for TBase64}
{$IFDEF UseHuge}
constructor TBase64.Create(AStream : TStream; ATextStream : TTextStream);
{$ELSE}
constructor TBase64.Create(AStream : TStream; ATextStream : TStringList);
{$ENDIF}
begin
inherited Create;
Stream:=AStream;
TextStream:=ATextStream;
ProgressStep:=10;
Table:='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
FillChar(A24Bits,SizeOf(A24Bits),0);
end;
procedure TBase64.DoProgress(Sender : TObject);
begin
if Assigned(FOnProgress) then
FOnProgress(Sender);
end;
procedure TBase64.DoStart(Sender : TObject);
begin
if Assigned(FOnStart) then
FOnStart(Sender);
end;
procedure TBase64.DoEnd(Sender : TObject);
begin
if Assigned(FOnEnd) then
FOnEnd(Sender);
end;
function TBase64.GenerateTxtBytes(tb : TBinBytes; NumOfBytes : byte) : string;
var
i,j,k,b,m : word;
s : string;
begin
k:=0;
FillChar(A24Bits,SizeOf(T24Bits),0);
for i:=1 to MaxChars do
begin
b:=tb[i];
for j:=7 DownTo 0 do
begin
m:=1 shl j;
if (b and m = m) then
A24Bits[k]:=true;
Inc(k);
end;
end;
s:=''; k:=0; m:=4*(MaxChars div 3);
for i:=1 to m do
begin
b:=0;
for j:=5 DownTo 0 do
begin
if A24Bits[k] then b:= b or (1 shl j);
Inc(k);
end;
s[i]:=Table[b+1];
end;
if (NumOfBytes=MaxChars) or (NumOfBytes mod 3=0) then
s[0]:=Char(4*NumOfBytes div 3)
else
begin
s[0]:=Char(4*NumOfBytes div 3+1);
while (Length(s) mod 4)<>0 do
s:=Concat(s,'=');
end;
Result:=s;
end;
procedure TBase64.Encode;
var
BytesRead : word;
ABinBytes : TBinBytes;
Total : LongInt;
begin
DoStart(Self);
TextStream.Clear;
Progress:=0; Total:=0; Canceled:=false;
try
repeat
FillChar(ABinBytes,SizeOf(TBinBytes),0);
BytesRead:=Stream.Read(ABinBytes,MaxChars);
Inc(Total,BytesRead);
{$IFDEF UseHuge}
TextStream.Write(GenerateTxtBytes(ABinBytes,BytesRead));
{$ELSE}
TextStream.Add(GenerateTxtBytes(ABinBytes,BytesRead));
{$ENDIF}
Progress:=Round(100*Total/Stream.Size);
if Progress mod ProgressStep = 0 then
DoProgress(Self);
Application.ProcessMessages;
until (BytesRead<MaxChars) or Canceled;
finally
Progress:=100;
DoProgress(Self);
if Canceled then TextStream.Clear;
DoEnd(Self);
end;
end;
function TBase64.ByteFromTable(Ch : Char) : byte;
var
i : byte;
begin
i:=1;
while (Ch<>Table[i]) and (i<=64) do Inc(i);
if i>64 then
begin
if Ch='=' then Result:=0
else raise EUUInvalidCharacter.Create;
end;
Result:=i-1;
end;
procedure TBase64.GenerateBinBytes(InS : string; BufPtr : pointer;
var BytesGenerated : word);
var
i,j,k,b,m : word;
InSLen : byte absolute InS;
ActualLen : byte;
begin
FillChar(BufPtr^,MaxChars,0);
FillChar(A24Bits,SizeOf(T24Bits),0);
k:=0;
for i:=1 to InSLen do
begin
b:=ByteFromTable(InS[i]);
for j:=5 DownTo 0 do
begin
m:=1 shl j;
if (b and m = m) then
A24Bits[k]:=true;
Inc(k);
end;
end;
k:=0;
if InSLen<>4*MaxChars div 3 then
begin
ActualLen:=3*InSLen div 4;
while InS[InSLen]='=' do
begin
Dec(ActualLen);
Dec(InSLen);
end;
end
else
ActualLen:=MaxChars;
for i:=1 to ActualLen do
begin
b:=0;
for j:=7 DownTo 0 do
begin
if A24Bits[k] then b:= b or (1 shl j);
Inc(k);
end;
byte(PChar((PChar(BufPtr)+i-1))^):=b;
end;
BytesGenerated:=i;
end;
procedure TBase64.Decode;
var
ATxtBytes : TTxtBytes;
BytesGenerated : word;
Total : LongInt;
s : string;
p : pointer;
{$IFNDEF UseHuge}
i : LongInt;
{$ENDIF}
begin
DoStart(Self);
Progress:=0;
Canceled:=false;
{$IFNDEF UseHuge}
i:=0;
{$ENDIF}
try
GetMem(p,MaxChars);
Total:=0;
repeat
FillChar(p^,MaxChars,0);
{$IFDEF UseHuge}
TextStream.Read(s);
{$ELSE}
s:=TextStream[i];
{$ENDIF}
GenerateBinBytes(s,p,BytesGenerated);
Stream.Write(p^,BytesGenerated);
Inc(Total,BytesGenerated);
{$IFDEF UseHuge}
Progress:=Round(100*Total/TextStream.Size);
{$ELSE}
Progress:=Round(100*i/(TextStream.Count-1));
{$ENDIF}
if Progress mod ProgressStep = 0 then
DoProgress(Self);
Application.ProcessMessages;
{$IFDEF UseHuge}
until (TextStream.Position>=TextStream.Size) or Canceled;
{$ELSE}
Inc(i);
until (i>=TextStream.Count);
{$ENDIF}
finally
Progress:=100;
DoProgress(Self);
FreeMem(p,MaxChars);
DoEnd(Self);
end;
end;
{implementation for TQuotedPrintable}
const
BufSize=$6000;
constructor TQuotedPrintable.Create(AStream : TStream; ALines : TStringList);
begin
Stream:=AStream;
Lines:=ALines;
Canceled:=false;
end;
procedure TQuotedPrintable.ReplaceHiChars(var s : string);
var
sLen : byte absolute s;
i : byte;
begin
i:=1;
while i<sLen do
begin
if Ord(s[i]) in [0..31,61,128..255] then
begin
Insert(Concat('=',IntToHex(Ord(s[i]),2)),s,i+1);
Delete(s,i,1);
Inc(i,2);
end;
Inc(i);
end;
end;
procedure TQuotedPrintable.ReformatParagraph(Buf : PChar; Len : Integer;
TL : TStringList);
var
i : Integer;
cp,sp : PChar;
s : string;
sLen : byte absolute s;
Finished : boolean;
begin
sp:=Buf;
TL.Clear;
repeat
cp:=sp+Len;
Finished:=cp>StrEnd(Buf);
if Finished then cp:=StrEnd(Buf)
else
begin
while (cp^<>' ') and (cp>sp) do Dec(cp);
if cp=sp then
cp:=sp+Len;
end;
sLen:=cp-sp;
move(sp^,s[1],sLen);
if not Finished then s:=Concat(s,'=');
ReplaceHiChars(s);
TL.Add(s);
sp:=cp;
until Finished;
end;
procedure TQuotedPrintable.Encode;
var
j : Integer;
Ch : Char;
s : string;
Buf : PChar;
Finished : boolean;
TempLines : TStringList;
begin
Buf:=StrAlloc(BufSize);
TempLines:=TStringList.Create;
try
repeat
{Read a paragraph}
j:=0;
FillChar(Buf^,BufSize,0);
repeat
if j>=BufSize then
raise EMIMEError.Create('Paragraph is too large');
Stream.Read(Ch,1);
if Stream.Position=Stream.Size then
begin
Finished:=true;
move(Ch,(Buf+j)^,1);
Inc(j);
end
else
if Ch in [^M,^J] then
begin
Finished:=true;
Stream.Read(Ch,1);
if not (Ch in [^M,^J])
then Stream.Position:=Stream.Position-1;
end
else
begin
Finished:=false;
move(Ch,(Buf+j)^,1);
Inc(j);
end;
Application.ProcessMessages;
until Finished;
ReformatParagraph(Buf,65,TempLines);
if TempLines.Count=0 then Lines.Add('')
else Lines.AddStrings(TempLines);
until (Stream.Position=Stream.Size) or Canceled;
finally
TempLines.Free;
StrDispose(Buf);
end;
end;
procedure TQuotedPrintable.ReplaceHex(var s : string);
var
i : byte;
sLen : byte absolute s;
Hex : byte;
begin
i:=1;
while i<sLen do
begin
if (s[i]='=') then
begin
try
Hex:=StrToInt('$'+Copy(s,i+1,2));
Delete(s,i,3);
Insert(Char(Hex),s,i);
except
on EConvertError do {Do nothing}
else raise;
end;
end;
Inc(i);
end;
end;
procedure TQuotedPrintable.Decode;
var
Buf : PChar;
i : Integer;
Finished : boolean;
s : string;
sLen : byte absolute s;
begin
Buf:=StrAlloc(BufSize);
i:=-1;
try
repeat
FillChar(Buf^,BufSize,0);
repeat
Inc(i);
s:=Lines[i];
ReplaceHex(s);
Finished:=(sLen=0) or (s[sLen]<>'=');
if not Finished then Dec(sLen)
else s:=Concat(s,^M^J);
s:=Concat(s,#00);
if StrLen(Buf)+sLen>=BufSize then
raise EMIMEError.Create('Paragraph is too large');
StrCat(Buf,@s[1]);
until Finished;
Stream.Write(Buf^,StrLen(Buf));
Application.ProcessMessages;
until (i=Lines.Count-1) or Canceled;
finally
StrDispose(Buf);
end;
end;
function GetContentType(const FileName : string) : string;
var
Ext : string[4];
begin
Ext:=UpperCase(ExtractFileExt(FileName));
if Ext='.AIF' then result:='audio/aiff'
else
if (Ext='.AU') or (Ext='.SND') then result:='audio/basic'
else
if Ext='.GIF' then result:='image/gif'
else
if Ext='.JPG' then result:='image/jpeg'
else
if Ext='.AVI' then result:='video/avi'
else
if Ext='.RTF' then result:='text/rtf'
else
if Ext='.HTM' then result:='text/html'
else
if Ext='.TXT' then result:='text/plain'
else
result:='application/octet-stream';
end;
function MakeUniqueID : string;
var
i : Integer;
begin
Randomize;
Result:='';
for i:=1 to 8 do
Result:=Concat(Result,IntToStr(Random(9)));
end;
end.